#import <Foundation/Foundation.h>
#import "PersistentDataType.h"
#import "NSArrayCustomSort.h"
#import "FileUtilities.h"

/**
 * A PersistentDataCollection is an object representing a
 * collection of data types that are stored on disk.
 *
 * All objects in the collection must conform to the 
 * PersistentDataType protocol.
 *
 * @author      James Lin
 * @version     0.7.5
 * @since       0.3.2
 * @see         PersistentDataType
 */
@interface PersistentDataCollection : NSObject {
	NSMutableDictionary* dataDictionary; // A dictionary of persistent data types
	NSString*            path;           // Absolute path at which this collection is stored
}

@property (nonatomic, retain) NSString* path;

/**
 * Initialize the PersistentDataCollection as an empty collection.
 * 
 * @param fileName  the name of the file in which to store this collection
 * @param subdir    the unique subdirectory holding all data for this collection
 * @return          the initialized empty PersistentDataCollection
 */
- (id)initWithEmptyFile:(NSString*)fileName 
	  usingSubdirectory:(NSString*)subdir;

/**
 * Initialize the PersistentDataCollection with existing persistent data.
 * 
 * If the file at the path is non-existent, one is created.
 *
 * @precondition    the file at the path is valid or non-existent
 * @param fileName  the path from which to load or store this collection
 * @param subdir    the unique subdirectory holding all data for this collection
 * @return          the initialized PersistentDataCollection
 */
- (id)initWithFile:(NSString*)fileName usingSubdirectory:(NSString*)subdir;

/**
 * Initialize the PersistentDataCollection with an array of data types.
 * 
 * @precondition     the data types are all valid and unique
 * @param dataTypes  the array of data types with which to initialize
 * @param fileName   the path at which to store this collection
 * @param subdir     the unique subdirectory holding all data for this collection
 * @return           the initialized PersistentDataCollection with specified data types
 */
- (id)initWithDataTypes:(NSArray*)events 
				   file:(NSString*)fileName 
	  usingSubdirectory:(NSString*)subdir;

/**
 * Create a new empty archive.
 *
 * @param fileName  the path at which to store this collection
 * @param subdir    the unique subdirectory holding all data for this collection
 */
- (void)resetArchiveWithFileName:(NSString*)fileName
			   usingSubdirectory:(NSString*)subdir;

/**
 * Retrieve the unique key used for archiving.
 *
 * Override to specify unique key if subclassing.
 *
 * @return  the key used for keyed archiving
 */
- (NSString*)getArchiveKey;

/**
 * Save the event collection data to archive.
 *
 * Sets the root object of the tree and recursively encodes every
 * persistent data type in the dictionary to archive.
 */
- (void)saveData;

/**
 * Load the event collection data from archive.
 *
 * Sets the root object of the tree and recursively decodes every
 * persistent data type in the archived dictionary.
 */
- (void)loadData;

/**
 * Add a persistent data type to the collection.
 * 
 * @precondition    the data type is unique in the collection
 * @param dataType  the data type to add
 */
- (void)addDataType:(id<PersistentDataType>)dataType;

/**
 * Add an array of persistent data types to the collection.
 *
 * @precondition     the data types are all unique in the collection
 * @param dataTypes  the array of data types to add
 */
- (void)addDataTypes:(NSArray*)dataTypes;

/**
 * Add another persistent data collection to this collection.
 *
 * @param dataCollection  the persistent data collection to add to this collection
 */
- (void)addDataCollection:(PersistentDataCollection*)dataCollection;

/**
 * Get the data types in the given list of data types that are in 
 * this collection.
 *
 * @param dataTypes  the list of data types of which to check intersection
 * @return           the data types in the given list that are in this collection
 */
- (NSArray*)intersectDataTypes:(NSArray*)dataTypes;

/**
 * Determine whether the given data type is in the collection.
 *
 * @param dataType  the data type of which to check existence
 * @return          YES if the data type is in the collection;
 *                  NO otherwise.
 */
- (BOOL)containsDataType:(id<PersistentDataType>)dataType;

/**
 * Retrieve size of collection.
 *
 * @return  the size of the collection as an integer
 */
- (int)size;

/**
 * Retrieve all data types in the collection.
 *
 * @return  an array of all data types in the collection
 */
- (NSArray*)getDataTypes;

/**
 * Find all data types whose keys contain any or all of the keywords 
 * in the given space-delimited keyword string.
 *
 * @precondition    keyword string is not nil
 * @param keyword   the case-insensitive search keyword string
 * @param matchAll  YES if all keywords in the keyword list must match;
 *                  NO if any keyword can match.
 * @return          an array of data types with suitable matches
 */
- (NSArray*)findDataTypesWithKeywordString:(NSString*)keyword 
						  matchAllKeywords:(BOOL)matchAll;

/**
 * Find all data types whose keys contain any or all of the keywords
 * in the given list of search keywords.
 *
 * If matching by any keyword in the keyword list, an additional sort
 * will be performed on the resulting list after the completed query.
 * The resulting list of events will be in non-increasing order of 
 * the number of keywords matched.
 *
 * @precondition    keywords are not nil
 * @param keywords  the list of case-insensitive search keywords
 * @param matchAll  YES if all keywords in the keyword list must match;
 *                  NO if any keyword can match.
 * @return          an array of data types with suitable matches
 */
- (NSArray*)findDataTypesWithKeywords:(NSArray*)keywords 
					 matchAllKeywords:(BOOL)matchAll;

/**
 * Retrieve the data type with the given key.
 *
 * @param key  the key of the data type to retrieve
 */
- (id<PersistentDataType>)getDataTypeWithKey:(NSString*)key;

/**
 * Remove a persistent data type from the collection.
 *
 * @param dataType  the dataType to remove
 */
- (void)removeDataType:(id<PersistentDataType>)dataType;

/**
 * Empty the collection.
 */
- (void)clear;

@end
